﻿using BenchmarkDotNet.Attributes;
using System.Text;

namespace SearchText
{
    [Config(typeof(MyConfig))]
    [MemoryDiagnoser]

    [Orderer(BenchmarkDotNet.Order.SummaryOrderPolicy.FastestToSlowest)]
    [RankColumn]

    public class UnsafeSearch
    {
        private readonly byte[] patternBytes = new byte[] { 0x01, 0x02, 0x03, 0x04,0x05,0x06,0x07,0x08,0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
        private byte[] fileBytes;
        private string filePath = "input2.bin";

        [GlobalSetup]
        public void Setup()
        {
            using (var stream = File.Open(filePath, FileMode.Open, FileAccess.Read))
            {
                fileBytes = new byte[stream.Length];
                stream.Read(fileBytes, 0, (int)stream.Length);
            }
        }



        //暴力搜素
        [Benchmark(Baseline = true)]
        public void Search()
        {
            List<int> positions = new List<int>();
            int patternLength = patternBytes.Length;

            for (int i = 0; i <= fileBytes.Length - patternLength; i++)
            {
                int match = 1;

                for (int j = 0; j < patternLength; j++)
                {
                    if (fileBytes[i + j] != patternBytes[j])
                    {
                        match = 0;
                        break;
                    }
                }

                if (match == 1)
                {
                    positions.Add(i);
                }
            }
        }

        //unsafe暴力搜素
        [Benchmark]
        public unsafe void UnsafeFind()
        {
            List<int> positions = new List<int>();
            fixed (byte* pFileBytes = fileBytes)
            fixed (byte* pPatternBytes = patternBytes)
            {
                byte* pFile = pFileBytes;
                byte* pPattern = stackalloc byte[patternBytes.Length];
                int patternLength = patternBytes.Length;

                for (int i = 0; i <= fileBytes.Length - patternLength; i++)
                {
                    byte* pCurrent = pFile + i;
                    byte* pPatternCurrent = pPattern;
                    int match = 1;

                    for (int j = 0; j < patternLength; j++)
                    {
                        if (*pCurrent++ != *pPatternCurrent++)
                        {
                            match = 0;
                            break;
                        }
                    }

                    if (match == 1)
                    {
                        positions.Add(i);
                    }
                }
            }
        }
        //KMP算法搜素
        [Benchmark]
        public void KMPSearch()
        {
            List<long> positions3 = new List<long>();
            int patternLength = patternBytes.Length;
            int[] next = new int[patternLength];
            ComputeNEXTArray(patternLength, next);
            int j = 0;

            for (int i = 0; i < fileBytes.Length; i++)
            {
                while (j > 0 && fileBytes[i] != patternBytes[j])
                {
                    j = next[j - 1];
                }

                if (fileBytes[i] == patternBytes[j])
                {
                    j++;
                }

                if (j == patternLength)
                {
                    positions3.Add((long)i - (patternLength - 1));
                    j = next[j - 1];
                }
            }
        }

        private void ComputeNEXTArray(int patternLength, int[] next)
        {
            next[0] = 0;
            int i = 1;
            int j = 0;

            while (i < patternLength)
            {
                if (patternBytes[i] == patternBytes[j])
                {
                    j++;
                    next[i] = j;
                    i++;
                }
                else
                {
                    if (j != 0)
                    {
                        j = next[j - 1];
                    }
                    else
                    {
                        next[i] = 0;
                        i++;
                    }
                }
            }
        }

        //unsafe的KMP算法
        [Benchmark]
        public unsafe void UnsafeKMPSearch()
        {
            List<long> positions3 = new List<long>();
            int patternLength = patternBytes.Length;
            int* next = stackalloc int[patternLength]; // 使用stackalloc分配内存
            UnsafeComputeNEXTArray(patternLength, next);
            int j = 0;

            for (int i = 0; i < fileBytes.Length; i++)
            {
                while (j > 0 && fileBytes[i] != patternBytes[j])
                {
                    j = next[j - 1];
                }

                if (fileBytes[i] == patternBytes[j])
                {
                    j++;
                }

                if (j == patternLength)
                {
                    positions3.Add((long)i - (patternLength - 1));
                    j = next[j - 1];
                }
            }
        }

        private unsafe void UnsafeComputeNEXTArray(int patternLength, int* next)
        {
            next[0] = 0;
            int i = 1;
            int j = 0;

            while (i < patternLength)
            {
                if (patternBytes[i] == patternBytes[j])
                {
                    j++;
                    next[i] = j;
                    i++;
                }
                else
                {
                    if (j != 0)
                    {
                        j = next[j - 1];
                    }
                    else
                    {
                        next[i] = 0;
                        i++;
                    }
                }
            }
        }


        //字符串搜索
        [Benchmark]
        public void ToStringSearch()
        {
            List<int> positions4 = new List<int>();
            var fileString = Encoding.UTF8.GetString(fileBytes);
            var patternString = Encoding.UTF8.GetString(patternBytes);

            if (string.IsNullOrEmpty(patternString) || string.IsNullOrEmpty(fileString))
            {
                return; // 如果模式字符串或文件字符串为空，则不执行搜索
            }

            int index = 0;
            while ((index = fileString.IndexOf(patternString, index)) != -1)
            {
                positions4.Add(index);
                index += patternString.Length; // 移动到找到的模式之后，继续搜索
                if (index >= fileString.Length) break; // 确保不超出字符串长度
            }
        }
    }
}